<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>

	<body>
	</body>
	<script>
		//未运用状态模式的样子
		//单动作条件判断每增加一个动作就需要添加一 个 判断
		var lastAction = '';

		function changeMario(action) {
			if(action == 'jump') {
				//跳跃动作
			} else if(action == 'move') {
				//移动动作
			} else {
				//默认情况
			}
			lastAction = action;
		}

		//复合动作对条件判断的开销是翻倍的
		var lastAction1 = '';
		var lastAction2 = '';

		function changeMario(action1, action2) {
			if(action1 == 'shoot') {
				//射击
			} else if(action1 == 'jump') {
				//跳跃
			} else if(action1 == 'move' && action2 == 'shoot') {
				//移动中射击
			} else if(action1 == 'jump' && action2 == 'shoot') {
				//跳跃中射击
			}
			//保留上一个动作
			lastAction1 = action1 || '';
			lastAction2 = action2 || '';
		}
		// 运用状态模式，创建超级玛丽状态类
		var Mariostate = function() {
			//内部状态私有变量
			var _currentState = {},
				//动作与状态方法映射
				states = {
					jump: function() {
						//跳跃
						console.log('jump');
					},
					move: function() {
						//移动
						console.log('move');
					},
					shoot: function() {
						//射击
						console.log('shot');
					},
					squat: function() {
						//蹲下
						console.log('squat');
					}
				};
			//动作控制类
			var Action = {
				//改变状态方法
				changeState: function() {
					//组合动作通过传递多个参数实现
					debugger
					var arg = arguments;
					//重置内部状态
					_currentState = {};
					//如果有动作则添加动作
					if(arg.length) {
						//遍历动作
						for(var i = 0, len = arg.length; i < len; i++) {
							//向内部状态中添加动作
							_currentState[arg[i]] = true;
						}
					}
					//返回动作控制类
					return this;
				},
				//执行动作
				goes: function() {
					console.log('触发一次动作');
					//遍历内部状态保存的动作
					for(var i in _currentState) {
						//如果该动作存在则执行
						states[i] && states[i]();
					}
					return this;
				}
			}
			//返回接口方法change、 gose
			return {
				change: Action.changeState,
				goes: Action.goes
			}
		}
		Mariostate()
			.change('jump', 'shoot') // 添加跳跃与设计动作
			.goes() //执行动作
			.goes() //执行动作
			.change('shoot') //添加射击动作
			.goes(); //执行动作
		//当然为了更安全我们还是实例化一下这个状态类， 这样我们使用的是对状态类的一个复制品， 这样无论你怎么使用，都可以放心了。
		//创建一个 超级玛丽
		var Mario = new Mariostate();
		Mario
			.change('jump', 'shoot') // 添加跳跃与设计动作
				.goes() //执行动作
				.goes() //执行动作
				.change('shoot') //添加射击动作
				.goes(); //执行动作
				// 输出结果:
				// 触发一次动作
				// jump
				// shoot
				// 触发一次动作
				// jump
				// shoot
				// 触发一次动作
				// shoot
	</script>

</html>